/*
 * TacticaBase.java
 *
 * Created on 26 de marzo de 2007, 22:09
 *
 */

package futbol.tacticas.concursantes2007.tikitaka.tactica;

import futbol.General;
import futbol.tacticas.*;
import futbol.tacticas.concursantes.Tactica;

import java.util.Vector;
import java.awt.Point;

/**
 *
 * @author Ismael Mariscal Mena
 */
public abstract class TacticaBase extends EntidadBase implements Tactica {
    
    Vector<Comando> comandos;
    MaquinaEstados entrenador;
    Balon balon;
    Equipo equipo;
    JugadorBase jugador[];
    Equipo contrario;
    int jugadorMasCercaBalon;
    int jugadorContrarioMasCercaBalon;
    int posesion; //0 Indica que nosotros poseemos el balon, 1 indica que lo posee el equipo contrario, 2 balon dividido
    int tiempoPartido = 0;
    int marcador[];
    double distancia_2[][]; //Distancias entre jugadores
    int distanciaGolpeo[][] = {{7, 15},{8, 17},{10, 20},{25, 38}};
  
    public abstract class JugadorBase extends EntidadBase {
        
        protected MaquinaEstados maquinaEstados;
        Point posicion;  //Posicion base del jugador
        Point pase;
        int jugador;
        
        public JugadorBase(int jugador, Point posicion)
        {
            super();
            this.jugador = jugador;
            this.posicion = posicion;
            distancia_2 = new double[23][23];
        }
        
        public Point getPosicion()
        {
//            return posicion;
            return equipo.getPosicion(jugador);
        }
        
        public Point getPosicionBase()
        {
            return posicion;
        }
        
        public boolean cercaBalon()
        {
            return (Math.pow(balon.getPosicionActual().x - equipo.getPosicion(jugador).x, 2) + Math.pow(balon.getPosicionActual().y - equipo.getPosicion(jugador).y, 2)) < 100;
        }
        
        public void tirarAPuerta()
        {
            Point p = equipo.getPosicion(jugador);
            //Aqu tiramos al centro de la portera, pero podemos ajustar ms el tiro dependiendo de dd estemos
            double angulo = General.getAngulo(p.x, p.y, 160, 0);
            double x = p.x + Math.cos(angulo) * 100;
            double y = p.y + Math.sin(angulo) * 100;
            comandos.add(new ComandoGolpearBola(jugador, x, y));
        }
        
        public void pasarA(int jugadorDestino)
        {
            Point pDestino = equipo.getPosicion(jugadorDestino);
            Point pJugador = equipo.getPosicion(jugador);
            double angulo = General.getAngulo(pJugador.x, pJugador.y, pDestino.x, pDestino.y);
            if (equipo.getVelocidad(jugador) >= 5)
                comandos.add(new ComandoGolpearBola(jugador, pJugador.x + Math.cos(angulo) * 200, pJugador.y + Math.sin(angulo) * 200));
            else
                comandos.add(new ComandoGolpearBola(jugador, pDestino.x, pDestino.y));
        }
        
        public void irAlBalon()
        {
            int velocidadBola = (int)balon.getVelocidad(), velocidadFinal = velocidadBola + 1;
            double tiempoBola, tiempo;
            Point posicionBalon;

            if (velocidadFinal >  15)
                velocidadFinal = 15;

            do
            {
                velocidadFinal--;
                tiempoBola = velocidadBola - velocidadFinal;
                posicionBalon = balon.getPosicion((int)tiempoBola);
                tiempo = (Util.distancia(posicionBalon, equipo.getPosicion(jugador)) - 9) / equipo.getVelocidad(jugador);
            } while (tiempo > tiempoBola);
//            if (posicionBalon.x < -160) posicionBalon.x = -160;
//            else if (posicionBalon.x > 160) posicionBalon.x = 160;
//            if (posicionBalon.y < -120) posicionBalon.y = -120;
//            else if (posicionBalon.y > 120) posicionBalon.y = 120;
//            System.out.println("Ir Al Baln: Jugador " + jugador + ":" + posicionBalon + "\n");
            comandos.add(new ComandoIrA(jugador, posicionBalon.x, posicionBalon.y));
        }
        
        public void llevarBalon(Point destino)
        {
            Point miJugador = equipo.getPosicion(jugador);
            int jugadorContrario = jugadorContrarioMasCercano();  //obtenerJugadorContrarioMasCercano
            Point posJugadorContrario = contrario.getPosicion(jugadorContrario);
            if (Util.distancia_2(miJugador, posJugadorContrario) < /*900*/625)
            {
                double angulo1 = General.getAngulo(miJugador.x, miJugador.y, posJugadorContrario.x, posJugadorContrario.y);
                double angulo = obtenerAngulo(jugadorContrario);
                double anguloDestino = General.getAngulo(miJugador.x, miJugador.y, destino.x, destino.y);
                double anguloa = General.corregirAngulo(angulo1 + angulo);
                double angulob = General.corregirAngulo(angulo1 - angulo);
//                System.out.println("Angulo a Contrario: " + angulo1);
//                System.out.println("Angulo a: " + anguloa);
//                System.out.println("Angulo b: " + angulob);
//                System.out.println("Angulo a Destino: " + anguloDestino);
                if ((anguloDestino < anguloa && anguloDestino > angulob) || (angulob > anguloa && ((anguloDestino < anguloa) || (anguloDestino > angulob))))
                {
                    double a = angulo1 - anguloDestino;
                    if (a < 0) a += 2 * Math.PI;
                    if (a > Math.PI)
//                    if (a < 0 || a > Math.PI)
                        a = anguloa;
                    else
                        a = angulob;
                    double x = miJugador.x + Math.cos(a) * 200;
                    double y = miJugador.y + Math.sin(a) * 200;
                    destino = new Point((int)x, (int)y);
                }
            }
            controlBalon(destino);
        }
        
        public void controlBalon(Point destino)
        {
            Point posicion = equipo.getPosicion(jugador);
            double distanciaDisparo, angulo = General.getAngulo(posicion.x, posicion.y, destino.x, destino.y);
            double distanciaDestino = General.getDistancia(posicion.x, posicion.y, destino.x, destino.y);
            double distanciaAlBalon = Util.distancia(posicion, balon.getPosicionActual());
            double distanciaBalonDestino = Util.distancia(balon.getPosicionActual(), destino);
//            if (distanciaDestino > 6) //Si an no hemos llegado al destino
//            {
                if (distanciaBalonDestino >= distanciaDestino)
                    distanciaDisparo = (double)distanciaGolpeo[equipo.getVelocidad(jugador) - 3][1];
                else if (distanciaAlBalon <= equipo.getVelocidad(jugador))
                    distanciaDisparo = (double)distanciaGolpeo[equipo.getVelocidad(jugador) - 3][0];
                else
                    distanciaDisparo = 0.0;
                posicion.x += Math.cos(angulo) * distanciaDisparo;
                posicion.y += Math.sin(angulo) * distanciaDisparo;
                comandos.add(new ComandoIrA(jugador, destino.x, destino.y));
                comandos.add(new ComandoGolpearBola(jugador, posicion.x, posicion.y));
//            }
        }
        
        public int jugadorContrarioMasCercano()
        {
            Point posicion = equipo.getPosicion(jugador);
            double distancia = Double.POSITIVE_INFINITY, d;
            int jugadorMasCercano = 0;
            for (int i = 0; i < 11; i++)
            {
                d = Util.distancia_2(posicion, contrario.getPosicion(i)) / contrario.getVelocidad_2(i);
                if (d < distancia)
                {
                    jugadorMasCercano = i;
                    distancia = d;
                }
            }
            return jugadorMasCercano;
        }
        
        /* jugador cerca nos indica si hay algn jugador contrario en una distancia < 625 con igual o mayor velocidad que nosotros */
        public boolean jugadorCerca()
        {
            for (int j = 0; j < 11; j++)
                if (distancia_2[jugador][j+11] < 625)
                    if (equipo.getVelocidad(jugador) <= contrario.getVelocidad(j))
                        return true;
            return false;
        }
        
        private double obtenerAngulo(int jugadorContrario)
        {   //Repasar que est bien
            double a = Util.distancia_2(equipo.getPosicion(jugador), contrario.getPosicion(jugadorContrario));
            double v = (contrario.getVelocidad(jugadorContrario)) / equipo.getVelocidad(jugador);
            if (a < 900) a = 900;
            double b = Math.sqrt((1.0 - Math.pow(v, 2.0)) * (a - 900)) - 30.0 * v;
//            if (a < 256) a = 256;
//            double b = Math.sqrt((1.0 - Math.pow(v, 2.0)) * (a - 256)) - 16.0 * v;
            return Math.acos(b / Math.sqrt(a));
        }  
    }    //Fin JugadorBase
    
    public TacticaBase()
    {
        distancia_2 = new double[23][23];
    }
    
    public void actualizarPartido(SituacionJugadores sPartido)
    {
        comandos=new Vector();
        equipo.setPosicionActual(sPartido.getMisJugadores());
        contrario.setPosicionActual(sPartido.getContrario());
        balon.setPosicionActual(sPartido.getBola());
        for (int i = 0; i < 11; i++)
        {
            for (int j = 0; j < 11; j++)
            {
                distancia_2[i][j+11] = distancia_2[j+11][i] = Util.distancia_2(equipo.getPosicion(i), contrario.getPosicion(j));
                distancia_2[i][j] = Util.distancia_2(equipo.getPosicion(i), equipo.getPosicion(j));
                distancia_2[i+11][j+11] = Util.distancia_2(contrario.getPosicion(i), contrario.getPosicion(j));
            }
            distancia_2[i][22] = distancia_2[22][i] = Util.distancia_2(equipo.getPosicion(i), balon.getPosicionActual());
            distancia_2[i+11][22] = distancia_2[22][i+11] = Util.distancia_2(contrario.getPosicion(i), balon.getPosicionActual());   
        }
    }
}
